/**
 * 等待项
 *
 * @author chitanda
 * @date 2022-12-12 18:12:27
 * @interface WaiterItem
 */
interface WaiterItem {
  resolve?: (bol?: boolean) => void;
  timeout?: unknown;
}

/**
 * 异步完成通知
 *
 * @author chitanda
 * @date 2022-12-12 18:12:57
 * @export
 * @class AwaitNotify
 */
export class AwaitNotify {
  /**
   * 所有等待的通知
   *
   * @author chitanda
   * @date 2022-12-12 18:12:52
   * @protected
   * @type {WaiterItem[]}
   */
  protected waiters: WaiterItem[] = [];

  /**
   * 等待完成
   *
   * @author chitanda
   * @date 2022-12-12 18:12:06
   * @param {number} [timeout=-1]
   * @return {*}  {Promise<void>}
   */
  wait(timeout: number = -1): Promise<void> {
    const waiter: WaiterItem = {};
    this.waiters.push(waiter);
    const promise = new Promise<void>(resolve => {
      let resolved = false;
      waiter.resolve = noRemove => {
        if (resolved) {
          return;
        }
        resolved = true;
        if (waiter.timeout) {
          clearTimeout(waiter.timeout as string);
          waiter.timeout = null;
        }
        if (!noRemove) {
          const pos = this.waiters.indexOf(waiter);
          if (pos > -1) {
            this.waiters.splice(pos, 1);
          }
        }
        resolve();
      };
    });
    // eslint-disable-next-line no-restricted-globals
    if (timeout > 0 && isFinite(timeout)) {
      waiter.timeout = setTimeout(() => {
        waiter.timeout = null;
        waiter.resolve!();
      }, timeout);
    }
    return promise;
  }

  /**
   * 通知最后一个订阅者完成
   *
   * @author chitanda
   * @date 2022-12-12 18:12:18
   */
  notify(): void {
    if (this.waiters.length > 0) {
      this.waiters.pop()!.resolve!(true);
    }
  }

  /**
   * 通知所有订阅者完成
   *
   * @author chitanda
   * @date 2022-12-12 18:12:36
   */
  notifyAll(): void {
    for (let i = this.waiters.length - 1; i >= 0; i--) {
      this.waiters[i].resolve!(true);
    }
    this.waiters = [];
  }
}
